 /**************************************************************************//**
 * @file    csv_parser.c
 * @author  İsmail SEZEN (email: sezenismail@gmail.com)
 * @date    13-05-2009 [12:20]
 *
 * <b>Description</b>
 *
 * This file contains helper functions about parsing csv formatted files content.\n
 *
 * Copyright (C) 2010 İsmail SEZEN
 *
 * <b>License</b>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *****************************************************************************/

/*Include Drectives*///{
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <array_helper.h>
#include <StringHelper.h>
//}

/* Function Prototypes *///{
/*Public*/
int csv_read_file(char*,char);
void csv_finalize();
/*Private*/
int get_file_properties(char*,int*, int*);
char** parse_line(const char*, int, char);
int read_file_to_array(char*, char***,char);
//}

/*Variables *///{
int _wbp_is_initialized = 0;
char ***csv_data;
int csv_rowCount = 0;
int csv_colCount = 0;
static int _fieldBufferSize = 4;
//}

/*! @name Public
 *  These functions are defined in the header file csv_parser.h */
//@{//{

/*! @brief Analyses and reads the CSV file
 *  @sa get_file_properties
 *  @sa arr_2d_char2p
 *  @sa read_file_to_array
 *  @param[in] *fileName File to be read for parsing
 *  @param[in] delimiter delimiter charachter for parsing
 *  @return Zero if  the operation is succeed otherwise returns non-zero.
 *  @retval 0 - Succeed else Fail */
int csv_read_file(char *fileName,char delimiter){
	if(get_file_properties(fileName,&csv_rowCount,&csv_colCount) ) {
		if((csv_data = arr_2d_char2p(csv_rowCount,csv_colCount)) != NULL) {
			return read_file_to_array(fileName, &csv_data[0],delimiter);
		}
	}
	printf("CSV_parser : Error reading file!\n");
	return !EXIT_FAILURE;
}

/*! @brief Frees all arrays and resources created in the csv manipulaton process */
void csv_finalize(){
	register int i = 0;
	register int j = 0;
	if(csv_data != NULL) {
		for(i=0;i<csv_rowCount;i++)
			for(j=0;j<csv_colCount;j++)
				free(csv_data[i][j]);
		printf("csv  resources released\n");
		//free(csv_data);
	}
}

//}//@}

/* Private Routines -------------------------------------------------------------------------------------------------------------*///{

/*! @brief Reads a line from the \a stream without new line char.
 *
 *  This function is alternative to the <b>stdio.h -> getline</b> function.
 *  Uses the <b>stdio.h -> getline</b> function internally but does not include
 *  the new line char in the line string presented b \a *lineptr.
 *
 *  @param[out] **lineptr This is a pointer to the read line char array in the memory
 *  @param[in] *n delimiter charachter for parsing
 *  @param[in] *stream File Stream
 *  @note This is a internal function
 *  @return Number of lines in the text file */
ssize_t getline2(char **lineptr, size_t *n, FILE *stream) {
	ssize_t len = getline(lineptr, n, stream);
	if(len!=-1){
		char* c = *lineptr+(--len);
		if(*c == '\n') *c = '\0';
	}
	return len;
}

/*! @brief Analyses the csv file and returns the couns of lines and columns.
 *
 *  This function reads the file and calculates the number of lines and columns.
 *  @sa sh_count_char
 *
 *  @param[in] *fileName is the file will be analyse.
 *  @param[out] *rowCount is a pointer and represents nuber of lines
 *  @param[out] *colCount is the pointer to the column count
 *  @return Returns the operation result
 *  @retval Succeed: Non-Zero | Fail: 0(Zero) */
int get_file_properties(char * fileName,int *rowCount, int *colCount) {
	int success = 0;
	*rowCount = 0;
	*colCount = 0;
	FILE * fl = fopen(fileName, "r");
	if (fl != NULL) {
		char * line = NULL;
		size_t len = 0;
		while (getline(&line, &len, fl) != -1) {
			register int fcount = sh_count_char( line , ';' ) + 1;
			if(*colCount <fcount) *colCount  = fcount;
			(* rowCount)++;
		}
		fclose(fl);
		success =1;
	}
	return success;
}

/*! @brief Parses the \a line string into fields by delimiter.
 *
 *  This function reads a line string and splits it into fields by delimiter.
 *  \a buffer_size shows a field's length as char.
 *  @sa sh_splitString
 *  @see http://www.daniweb.com/code/snippet216535.html
 *  @param[in] *line is a pointer to the char array
 *  @param[in] *buffer_size i maxs size of th a field.
 *  @param[in] delimiter delimiter charachter for parsing
 *  @return Returns Field array. Every index contains a string. */
char** parse_line(const char* line, int buffer_size, char delimiter) {
	return sh_splitString(line, buffer_size, delimiter);
}

/*! @brief Reads the file content into a 2D array using delimiter char.
 *
 *  This function reads lines one by one and parses every line into fields by using delimiter char.
 *  Returns all file content as splitted fields by \a ***p_arr variable.
 *  @sa getline2
 *  @see http://www.koders.com/c/fidA7888C848669A132141BDD56E1B0904710CB72AF.aspx?s=fopen#L11
 *  @param[in] *fileName is the file will be read
 *  @param[out] ***p_arr is the pointer to the result aray. (Should be null at the begining.)
 *  @param[in] delimiter delimiter charachter for splitting.
 *  @return Returns operation result.
 *  @retval Success:0 | Fail:Non-Zero */
int read_file_to_array(char *fileName, char*** p_arr, char delimiter) {
	int success = 0;
	size_t len = 0;
	char * line = NULL;
	FILE * fl = fopen(fileName, "r");
	if ( fl ) {
		while (getline2(&line, &len, fl) != -1) {
			*(p_arr++) = parse_line(line,_fieldBufferSize,delimiter);
		}
		fclose(fl);
		success = 1;
	}
	return success;
}

//}
